// (c) Copyright Alf P. Steinbach 2008.  Changes marked "APS".
// Use, modification and distribution are subject to the "New BSD License"
// as listed at <url: http://www.opensource.org/licenses/bsd-license.php>.
//
// <original comment>
// (C) Howard Hinnant 2004
// (C) Jonathan Turkanis 2004
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt.)
//
//
// Contains type traits machinery for incomplete arrays. MPL compatibility
// is included for completeness, but is not necessary for the current 
// application.
// </original comment>

#ifndef ALFS_MOVE_PTR_ARRAYS_HPP            // APS: Changed include guard.
#define ALFS_MOVE_PTR_ARRAYS_HPP
#include    <alfs/config.hpp>

#include <boost/config.hpp> // BOOST_STATIC_CONSTANT.
#include <boost/mpl/aux_/lambda_support.hpp>
#include <boost/mpl/and.hpp>
#include <boost/mpl/bool.hpp>
#include <boost/mpl/identity.hpp>
#include <boost/mpl/if.hpp>
#include <boost/type_traits/is_array.hpp>
#include <boost/type_traits/is_convertible.hpp>
#include <boost/type_traits/is_same.hpp>
#include <boost/type_traits/remove_bounds.hpp>
#include <boost/type_traits/remove_cv.hpp>
#include <boost/utility/enable_if.hpp>

namespace alfs{ namespace jt{ namespace move_ptrs { // APS: boost::move_ptrs -> alfs::jt::move_ptrs.

// From Howard Hinnant.
template<typename T, typename U>
struct is_array_convertible {
    typedef typename boost::remove_bounds<T>::type      t_element;  // APS: added boost::.
    typedef typename boost::remove_bounds<U>::type      u_element;  // APS: added boost::. 
    typedef typename boost::remove_cv<t_element>::type  t_base;     // APS: added boost::. 
    typedef typename boost::remove_cv<u_element>::type  u_base;     // APS: added boost::.
    typedef typename 
            boost::mpl::and_<                                       // APS: added boost::.
                boost::is_array<T>,
                boost::is_array<U>,                                 // APS: added boost::.
                boost::is_same<t_base, u_base>,                     // APS: added boost::.
                boost::is_convertible<t_element*, u_element*>       // APS: added boost::.
            >::type                                     type;
    BOOST_STATIC_CONSTANT(bool, value = type::value);
    BOOST_MPL_AUX_LAMBDA_SUPPORT(2, is_array_convertible, (T, U))
};

template<typename T, typename U>
struct is_smart_ptr_convertible 
    : boost::mpl::if_<                                              // APS: added boost::.
          boost::is_array<T>,
          is_array_convertible<T, U>,
          boost::is_convertible<T*, U*>                             // APS: added boost::.
      >::type
    { };

#ifndef BOOST_NO_SFINAE
    template<typename Src, typename Tgt, typename T = void>
    struct enable_if_convertible 
        : boost::enable_if<                                         // APS: added boost::.
              is_smart_ptr_convertible<Src, Tgt>,
              T
          >
        { };
#else
    template<typename Src, typename Tgt, typename T = void>
    struct enable_if_convertible : boost::mpl::identity<T> { };     // APS: added boost::.
#endif

} } }  // alfs::jt::move_ptrs

#endif      // #ifndef ALFS_MOVE_PTR_ARRAYS_HPP
